 /**
@file     rngLib.c 
@author   zhangya
@date	  2017-07-19
@version  v1.0 Copyright (C) 2017 - All Rights Reserved
@warning  
***************************************************************/
/*
This library provides routines for creating and using ring buffers, which
are first-in-first-out circular buffers.  The routines simply manipulate
the ring buffer data structure; no kernel functions are invoked.  In
particular, ring buffers by themselves provide no task synchronization or
mutual exclusion.

INCLUDE FILES: rngLib.h
*/

/* LINTLIBRARY */
#include "rngLib.h"
#include <string.h>

#define bcopy(src,dest,len) memcpy((dest), (src), (len))

#define min(_a, _b) ((_a)>(_b)?(_b):(_a))

/*******************************************************************************
*
* rngCreate - create an empty ring buffer
*
* This routine creates a ring buffer of size <nbytes>, and initializes
* it.  Memory for the buffer is allocated from the system memory partition.
*
* RETURNS
* The ID of the ring buffer, or NULL if memory cannot be allocated.
*/
#ifdef USE_UNCALLED_CODE
RING_ID rngCreate
(
 int16_t nbytes          /* number of bytes in ring buffer */
)
{
	int8_t *buffer;
	RING_ID ringId = (RING_ID)malloc(sizeof (RING));

	if (ringId == NULL)
	{
		return (NULL);
	}

	/* bump number of bytes requested because ring buffer algorithm
	* always leaves at least one empty byte in buffer */

	buffer = (int8_t *)malloc((unsigned) ++nbytes);

	if (buffer == NULL)
	{
		free ((int8_t *)ringId);
		return (NULL);
	}

	ringId->bufSize = nbytes;
	ringId->buf	    = buffer;

	rngFlush (ringId);

	return (ringId);
}

/*******************************************************************************
*
* rngDelete - free a ring buffer
*
* This routine deletes a specified ring buffer.
* Any data currently in the buffer will be lost.
*
* RETURNS: N/A
*/

void rngFree
(
 RING_ID ringId         /* ring buffer to free */
 )
{
	free (ringId->buf);
	free ((int8_t *)ringId);
}
#endif

/*******************************************************************************
*
* rngFlush - make a ring buffer empty
*
* This routine initializes a specified ring buffer to be empty.
* Any data currently in the buffer will be lost.
*
* RETURNS: N/A
*/

void rngFlush
(
 RING_ID ringId         /* ring buffer to initialize */
 )
{
	ringId->pToBuf   = 0;
	ringId->pFromBuf = 0;
}

/*******************************************************************************
*
* rngBufGet - get bytes into a ring buffer
*
* This routine gets bytes from <buffer> into ring buffer <ringId>.  The
* specified number of bytes will be put into the ring, up to the number of
* bytes available in the ring.
*
* INTERNAL
* Always leaves at least one byte empty between pToBuf and pFromBuf, to
* eliminate ambiguities which could otherwise occur when the two pointers
* are equal.
*
* RETURNS:
* The number of bytes actually put into the ring buffer;
* it may be less than number requested, even zero,
* if there is insufficient room in the ring buffer at the time of the call.
*/

int16_t rngBufGet
(
 RING_ID rngId,         /* ring buffer to get data from      */
 uint8_t *buffer,            /* pointer to buffer to receive data */
 int16_t maxbytes           /* maximum number of bytes to get    */
 )
{
	int16_t bytesgot;
	int16_t pToBuf;
	int16_t bytes2;
	int16_t pRngTmp ;

	pToBuf = rngId->pToBuf;

	if (pToBuf >= rngId->pFromBuf)
	{
		/* pToBuf has not wrapped around */

		bytesgot = min (maxbytes, pToBuf - rngId->pFromBuf);
		bcopy (&rngId->buf[rngId->pFromBuf], buffer, bytesgot);
		rngId->pFromBuf += bytesgot;
	}
	else
	{
		/* pToBuf has wrapped around.  Grab chars up to the end of the
		* buffer, then wrap around if we need to. */

		bytesgot = min (maxbytes, rngId->bufSize - rngId->pFromBuf);
		bcopy (&rngId->buf[rngId->pFromBuf], buffer, bytesgot);
		pRngTmp = rngId->pFromBuf + bytesgot;

		/* If pFromBuf is equal to bufSize, we've read the entire buffer,
		* and need to wrap now.  If bytesgot < maxbytes, copy some more chars
		* in now. */

		if (pRngTmp == rngId->bufSize)
		{
			bytes2 = min (maxbytes - bytesgot, pToBuf);
			bcopy (rngId->buf, buffer + bytesgot, bytes2);
			rngId->pFromBuf = bytes2;
			bytesgot += bytes2;
		}
		else
		{
			rngId->pFromBuf = pRngTmp;
		}
	}
	return (bytesgot);
}
/*******************************************************************************
*
* rngBufGetOne - get one bytes into a ring buffer
*
* This routine gets bytes from <buffer> into ring buffer <ringId>.  The
* specified number of bytes will be put into the ring, up to the number of
* bytes available in the ring.
*
* INTERNAL
* Always leaves at least one byte empty between pToBuf and pFromBuf, to
* eliminate ambiguities which could otherwise occur when the two pointers
* are equal.
*
* RETURNS:
* The number of bytes actually put into the ring buffer;
* it may be less than number requested, even zero,
* if there is insufficient room in the ring buffer at the time of the call.
*/
int8_t rngBufGetOne
(
 RING_ID rngId, 			/* ring buffer to put data into  */
 uint8_t *value					/* pointer to buffer to receive data */
)
{
	int16_t pToBuf;

	pToBuf = rngId->pToBuf;
	if (pToBuf == rngId->pFromBuf)
		return 0;

	*value = rngId->buf[rngId->pFromBuf];
	rngId->pFromBuf++;
	if (rngId->pFromBuf >= rngId->bufSize)
		rngId->pFromBuf = 0;

	return 1;
}

/*******************************************************************************
*
* rngBufPut - put bytes into a ring buffer
*
* This routine puts bytes from <buffer> into ring buffer <ringId>.  The
* specified number of bytes will be put into the ring, up to the number of
* bytes available in the ring.
*
* INTERNAL
* Always leaves at least one byte empty between pToBuf and pFromBuf, to
* eliminate ambiguities which could otherwise occur when the two pointers
* are equal.
*
* RETURNS:
* The number of bytes actually put into the ring buffer;
* it may be less than number requested, even zero,
* if there is insufficient room in the ring buffer at the time of the call.
*/

int16_t rngBufPut
(
 RING_ID rngId,         /* ring buffer to put data into  */
 uint8_t *buffer,            /* buffer to get data from       */
 int16_t nbytes             /* number of bytes to try to put */
 )
{
	   int16_t bytesput;
	   int16_t pFromBuf;
	   int16_t bytes2;

	//int16_t pRngTmp = 0;
	 pFromBuf = rngId->pFromBuf;

	if (pFromBuf > rngId->pToBuf)
	{
		/* pFromBuf is ahead of pToBuf.  We can fill up to two bytes
		* before it */

		bytesput = min (nbytes, pFromBuf - rngId->pToBuf - 1);
		bcopy (buffer, &rngId->buf[rngId->pToBuf], bytesput);
		rngId->pToBuf += bytesput;
	}
	else if (pFromBuf == 0)
	{
		/* pFromBuf is at the beginning of the buffer.  We can fill till
		* the next-to-last element */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf - 1);
		bcopy (buffer, &rngId->buf[rngId->pToBuf], bytesput);
		rngId->pToBuf += bytesput;
	}
	else
	{
		/* pFromBuf has wrapped around, and its not 0, so we can fill
		* at least to the end of the ring buffer.  Do so, then see if
		* we need to wrap and put more at the beginning of the buffer. */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf);
		if(bytesput > 0)
		{
		  	bcopy (buffer, &(rngId->buf[rngId->pToBuf]), bytesput);
		}
		rngId->pToBuf = rngId->pToBuf + bytesput;

		if (rngId->pToBuf == rngId->bufSize)
		{
			/* We need to wrap, and perhaps put some more chars */

			bytes2 = min (nbytes - bytesput, pFromBuf - 1);

			if(bytes2 > 0)
			{
			    bcopy (buffer + bytesput, rngId->buf, bytes2);
			}
			rngId->pToBuf = bytes2;
			bytesput += bytes2;
		}
	}
	return (bytesput);
}
/*******************************************************************************
*
* rngBufPutOne - put one bytes into a ring buffer
*
* This routine puts bytes from <buffer> into ring buffer <ringId>.  The
* specified number of bytes will be put into the ring, up to the number of
* bytes available in the ring.
*
* INTERNAL
* Always leaves at least one byte empty between pToBuf and pFromBuf, to
* eliminate ambiguities which could otherwise occur when the two pointers
* are equal.
*
* RETURNS:
* The number of bytes actually put into the ring buffer;
* it may be less than number requested, even zero,
* if there is insufficient room in the ring buffer at the time of the call.
*/
int8_t rngBufPutOne
(
 RING_ID rngId, 			/* ring buffer to put data into  */
 int8_t value					/* buffer to get data from       */
)
{
	int16_t pFromBuf;

	pFromBuf = rngId->pFromBuf;
	if (pFromBuf > rngId->pToBuf)
	{
		if ((pFromBuf - rngId->pToBuf - 1) <= 0)
			return 0;
	}
	else if (pFromBuf == 0)
	{
		if ((rngId->bufSize - rngId->pToBuf - 1) <= 0)
			return 0;
	}

	rngId->buf[rngId->pToBuf] = value;
	rngId->pToBuf++;
	if (rngId->pToBuf >= rngId->bufSize)
		rngId->pToBuf = 0;

	return 1;
}


/*******************************************************************************
*
* rngIsEmpty - test if a ring buffer is empty
*
* This routine determines if a specified ring buffer is empty.
*
* RETURNS:
* TRUE if empty, FALSE if not.
*/
int16_t rngIsEmpty
(
 RING_ID ringId      /* ring buffer to test */
)
{
	return (ringId->pToBuf == ringId->pFromBuf);
}

/*******************************************************************************
*
* rngIsFull - test if a ring buffer is full (no more room)
*
* This routine determines if a specified ring buffer is completely full.
*
* RETURNS:
* TRUE if full, FALSE if not.
*/

int16_t rngIsFull
(
 RING_ID ringId         /* ring buffer to test */
 )
{
	int16_t n = ringId->pToBuf - ringId->pFromBuf + 1;

	return ((n == 0) || (n == ringId->bufSize));
}

/*******************************************************************************
*
* rngFreeBytes - determine the number of free bytes in a ring buffer
*
* This routine determines the number of bytes currently unused in a specified
* ring buffer.
*
* RETURNS: The number of unused bytes in the ring buffer.
*/
#ifdef USED_UNCALLEN_FUNCTION
int16_t rngFreeBytes
(
 RING_ID ringId         /* ring buffer to examine */
 )
{
	int16_t n = ringId->pFromBuf - ringId->pToBuf - 1;

	if (n < 0)
	{
		n += ringId->bufSize;
	}

	return (n);
}
#endif

/*******************************************************************************
*
* rngNBytes - determine the number of bytes in a ring buffer
*
* This routine determines the number of bytes currently in a specified
* ring buffer.
*
* RETURNS: The number of bytes filled in the ring buffer.
*/
int16_t rngNBytes
(
 RING_ID ringId         /* ring buffer to be enumerated */
 )
{
	int16_t n = ringId->pToBuf - ringId->pFromBuf;

	if (n < 0)
	{
		n += ringId->bufSize;
	}
	return (n);
}
/*******************************************************************************
*
* rngDelete - delete the number of bytes in a ring buffer
*
* This routine determines the number of bytes currently in a specified
* ring buffer.
*
* RETURNS: The number of bytes filled in the ring buffer.
*/

int16_t rngDelete
(
 RING_ID rngId,
 int16_t nbytes
)
{
	int16_t bytesput;
	int16_t pFromBuf;
	int16_t bytes2;

	//int16_t pRngTmp = 0;
	pFromBuf = rngId->pFromBuf;

	if (pFromBuf > rngId->pToBuf)
	{
		/* pFromBuf is ahead of pToBuf.  We can fill up to two bytes
		* before it */

		bytesput = min (nbytes, pFromBuf - rngId->pToBuf - 1);
		rngId->pToBuf += bytesput;
	}
	else if (pFromBuf == 0)
	{
		/* pFromBuf is at the beginning of the buffer.	We can fill till
		* the next-to-last element */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf - 1);
		rngId->pToBuf += bytesput;
	}
	else
	{
		/* pFromBuf has wrapped around, and its not 0, so we can fill
		* at least to the end of the ring buffer.  Do so, then see if
		* we need to wrap and put more at the beginning of the buffer. */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf);
		rngId->pToBuf = rngId->pToBuf + bytesput;

		if (rngId->pToBuf == rngId->bufSize)
		{
			/* We need to wrap, and perhaps put some more chars */

			bytes2 = min (nbytes - bytesput, pFromBuf - 1);
			rngId->pToBuf = bytes2;
			bytesput += bytes2;
		}
	}
	return (bytesput);
}

/*******************************************************************************
*
* rngPutAhead - put a byte ahead in a ring buffer without moving ring pointers
*
* This routine writes a byte into the ring, but does not move the ring buffer
* pointers.  Thus the byte will not yet be available to rngBufGet() calls.
* The byte is written <offset> bytes ahead of the next input location in the
* ring.  Thus, an offset of 0 puts the byte in the same position as would
* RNG_ELEM_PUT would put a byte, except that the input pointer is not updated.
*
* Bytes written ahead in the ring buffer with this routine can be made available
* all at once by subsequently moving the ring buffer pointers with the routine
* rngMoveAhead().
*
* Before calling rngPutAhead(), the caller must verify that at least
* <offset> + 1 bytes are available in the ring buffer.
*
* RETURNS: N/A
*/
#ifdef USE_UNCALLED_CODE
void rngPutAhead
(
 RING_ID ringId,   /* ring buffer to put byte in    */
 int8_t byte,             /* byte to be put in ring        */
 int16_t offset             /* offset beyond next input byte where to put byte */
 )
{
	int16_t n = ringId->pToBuf + offset;

	if (n >= ringId->bufSize)
	{
		n -= ringId->bufSize;
	}

	*(ringId->buf + n) = byte;
}
/*******************************************************************************
*
* rngMoveAhead - advance a ring pointer by <n> bytes
*
* This routine advances the ring buffer input pointer by <n> bytes.  This makes
* <n> bytes available in the ring buffer, after having been written ahead in
* the ring buffer with rngPutAhead().
*
* RETURNS: N/A
*/

void rngMoveAhead
(
 RING_ID ringId,  /* ring buffer to be advanced                  */
 int16_t n            /* number of bytes ahead to move input pointer */
 )
{
	n += ringId->pToBuf;

	if (n >= ringId->bufSize)
	{
		n -= ringId->bufSize;
	}

	ringId->pToBuf = n;
}
#endif

int16_t rngBufGetNoDel (RING_ID rngId, uint8_t *buffer, int16_t maxbytes)
{
	int16_t retval;
	int16_t temp=rngId->pFromBuf;
	retval=rngBufGet(rngId, buffer,  maxbytes);
	rngId->pFromBuf=temp;

	return retval;
}

#ifdef USE_UNCALLED_CODE
void rngMoveRead
(
 RING_ID ringId,  /* ring buffer to be advanced                  */
 int16_t n            /* number of bytes ahead to move input pointer */
 )
{
	n += ringId->pFromBuf;

	if (n >= ringId->bufSize)
	{
		n -= ringId->bufSize;
	}

	ringId->pFromBuf = n;
}
#endif

#if 0
/*test*/
int16_t rngTestBufPut
(
 RING_ID rngId,         /* ring buffer to put data into  */
 int8_t *buffer,               /* buffer to get data from       */
 int16_t nbytes                   /* number of bytes to try to put */
 )
{
	int16_t bytesput = 0;
	int16_t pFromBuf = rngId->pFromBuf;
	int16_t bytes2;
	int16_t pRngTmp = 0;

	if (pFromBuf > rngId->pToBuf)
	{
		/* pFromBuf is ahead of pToBuf.  We can fill up to two bytes
		* before it */

		bytesput = min (nbytes, pFromBuf - rngId->pToBuf - 1);
		bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
		rngId->pToBuf += bytesput;
	}
	else if (pFromBuf == 0)
	{
		/* pFromBuf is at the beginning of the buffer.  We can fill till
		* the next-to-last element */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf - 1);
		bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
		rngId->pToBuf += bytesput;
	}
	else
	{
		/* pFromBuf has wrapped around, and its not 0, so we can fill
		* at least to the end of the ring buffer.  Do so, then see if
		* we need to wrap and put more at the beginning of the buffer. */

		bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf);
		bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
		pRngTmp = rngId->pToBuf + bytesput;

		if (pRngTmp == rngId->bufSize)
		{
			/* We need to wrap, and perhaps put some more chars */

			bytes2 = min (nbytes - bytesput, pFromBuf - 1);
			bcopy (buffer + bytesput, rngId->buf, bytes2);
			rngId->pToBuf = bytes2;
			bytesput += bytes2;
		}
		else
		{
			rngId->pToBuf = pRngTmp;
		}
	}
	return (bytesput);
}

int16_t rngTestBufGet
(
 RING_ID rngId,         /* ring buffer to get data from      */
 int8_t *buffer,               /* pointer to buffer to receive data */
 int16_t maxbytes                /* maximum number of bytes to get    */
 )
{
	int16_t bytesgot = 0;
	int16_t pToBuf = rngId->pToBuf;
	int16_t bytes2;
	int16_t pRngTmp = 0;

	if (pToBuf >= rngId->pFromBuf)
	{
		/* pToBuf has not wrapped around */

		bytesgot = min (maxbytes, pToBuf - rngId->pFromBuf);
		bcopy (&rngId->buf [rngId->pFromBuf], buffer, bytesgot);
		rngId->pFromBuf += bytesgot;
	}
	else
	{
		/* pToBuf has wrapped around.  Grab chars up to the end of the
		* buffer, then wrap around if we need to. */

		bytesgot = min (maxbytes, rngId->bufSize - rngId->pFromBuf);
		bcopy (&rngId->buf [rngId->pFromBuf], buffer, bytesgot);
		pRngTmp = rngId->pFromBuf + bytesgot;

		/* If pFromBuf is equal to bufSize, we've read the entire buffer,
		* and need to wrap now.  If bytesgot < maxbytes, copy some more chars
		* in now. */

		if (pRngTmp == rngId->bufSize)
		{
			bytes2 = min (maxbytes - bytesgot, pToBuf);
			bcopy (rngId->buf, buffer + bytesgot, bytes2);
			rngId->pFromBuf = bytes2;
			bytesgot += bytes2;
		}
		else
		{
			rngId->pFromBuf = pRngTmp;
		}
	}
	return (bytesgot);
}
#endif

